import datetime
import hashlib

from django.test import RequestFactory, TestCase, override_settings
from django.urls import reverse
from django.utils import timezone
from djconfig.utils import override_djconfig

from spirit.comment.bookmark.models import CommentBookmark
from spirit.comment.models import Comment
from spirit.core.tests import utils

from . import utils as utils_topic
from .forms import TopicForm
from .models import Topic
from .notification.models import TopicNotification
from .unread.models import TopicUnread


class TopicViewTest(TestCase):
    def setUp(self):
        utils.cache_clear()
        self.user = utils.create_user()

    @override_settings(ST_TESTS_RATELIMIT_NEVER_EXPIRE=True)
    def test_topic_publish(self):
        """
        POST, create topic
        """
        self.assertEqual(len(Topic.objects.all()), 0)

        utils.login(self)
        category = utils.create_category()
        form_data = {"comment": "foo", "title": "foobar", "category": category.pk}
        response = self.client.post(reverse("spirit:topic:publish"), form_data)
        topic = Topic.objects.last()
        expected_url = topic.get_absolute_url()
        self.assertRedirects(response, expected_url, status_code=302)
        self.assertEqual(len(Topic.objects.all()), 1)

        # ratelimit
        response = self.client.post(reverse("spirit:topic:publish"), form_data)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(Topic.objects.all()), 1)

        # get
        response = self.client.get(reverse("spirit:topic:publish"))
        self.assertEqual(response.status_code, 200)

    @override_settings(ST_TESTS_RATELIMIT_NEVER_EXPIRE=True)
    def test_topic_publish_validate(self):
        """
        Should validate all forms even when errors
        """
        self.assertEqual(len(Topic.objects.all()), 0)

        utils.login(self)
        no_data = {}
        response = self.client.post(reverse("spirit:topic:publish"), no_data)
        self.assertEqual(len(Topic.objects.all()), 0)
        self.assertTrue(bool(response.context["form"].errors))
        self.assertTrue(bool(response.context["cform"].errors))
        self.assertEqual(len(list(response.context["messages"])), 0)

        # No rate-limit
        category = utils.create_category()
        form_data = {"comment": "foo", "title": "foobar", "category": category.pk}
        self.client.post(reverse("spirit:topic:publish"), form_data)
        self.assertEqual(len(Topic.objects.all()), 1)

    def test_topic_publish_long_title(self):
        """
        POST, create topic with long title
        """
        utils.login(self)
        category = utils.create_category()
        title = "a" * 255
        form_data = {"comment": "foo", "title": title, "category": category.pk}
        response = self.client.post(reverse("spirit:topic:publish"), form_data)
        self.assertEqual(response.status_code, 302)
        self.assertEqual(len(Topic.objects.all()), 1)
        self.assertEqual(Topic.objects.last().slug, title[:50])

    @override_settings(ST_TESTS_RATELIMIT_NEVER_EXPIRE=True)
    def test_topic_publish_in_category(self):
        """
        POST, create topic in category
        """
        utils.login(self)
        category = utils.create_category()
        form_data = {"comment": "foo", "title": "foobar", "category": category.pk}
        response = self.client.post(
            reverse("spirit:topic:publish", kwargs={"category_id": category.pk}),
            form_data,
        )
        topic = Topic.objects.last()
        expected_url = topic.get_absolute_url()
        self.assertRedirects(response, expected_url, status_code=302)

        # ratelimit
        response = self.client.post(
            reverse("spirit:topic:publish", kwargs={"category_id": category.pk}),
            form_data,
        )
        self.assertEqual(response.status_code, 200)

    def test_topic_publish_in_subcategory(self):
        """
        POST, create topic in subcategory
        """
        utils.login(self)
        category = utils.create_category()
        subcategory = utils.create_subcategory(category)
        form_data = {"comment": "foo", "title": "foobar", "category": subcategory.pk}
        response = self.client.post(
            reverse("spirit:topic:publish", kwargs={"category_id": subcategory.pk}),
            form_data,
        )
        topic = Topic.objects.last()
        expected_url = topic.get_absolute_url()
        self.assertRedirects(response, expected_url, status_code=302)

    def test_topic_publish_invalid_category(self):
        """
        invalid topic category
        """
        utils.login(self)
        response = self.client.get(
            reverse("spirit:topic:publish", kwargs={"category_id": str(99)})
        )
        self.assertEqual(response.status_code, 404)

    @override_settings(ST_DOUBLE_POST_THRESHOLD_MINUTES=10)
    def test_topic_publish_double_post(self):
        """
        Should prevent double posts
        """
        utils.login(self)
        category = utils.create_category()
        topic_title = "title foobar"

        # First post
        self.client.post(
            reverse("spirit:topic:publish"),
            {"comment": "foo", "title": topic_title, "category": category.pk},
        )
        self.assertEqual(len(Topic.objects.all()), 1)

        # Double post
        utils.cache_clear()  # Clear rate limit
        response = self.client.post(
            reverse("spirit:topic:publish"),
            {"comment": "foo", "title": topic_title, "category": category.pk},
        )
        self.assertEqual(len(Topic.objects.all()), 1)  # Prevented!

        self.assertRedirects(
            response,
            expected_url=category.get_absolute_url(),
            status_code=302,
            target_status_code=200,
        )

        # New post
        utils.cache_clear()  # Clear rate limit
        self.client.post(
            reverse("spirit:topic:publish"),
            {"comment": "foo", "title": "new topic", "category": category.pk},
        )
        self.assertEqual(len(Topic.objects.all()), 2)

    @override_settings(ST_DOUBLE_POST_THRESHOLD_MINUTES=10)
    def test_topic_publish_same_post_into_another_topic(self):
        """
        Should not prevent from posting the same topic into another category
        """
        utils.login(self)
        category = utils.create_category()
        category_another = utils.create_category()
        topic_title = "title foobar"

        self.client.post(
            reverse("spirit:topic:publish"),
            {"comment": "foo", "title": topic_title, "category": category.pk},
        )
        self.assertEqual(len(Topic.objects.all()), 1)

        utils.cache_clear()  # Clear rate limit
        self.client.post(
            reverse("spirit:topic:publish"),
            {"comment": "foo", "title": topic_title, "category": category_another.pk},
        )
        self.assertEqual(len(Topic.objects.all()), 2)

    def test_topic_update(self):
        """
        POST, update topic
        """
        utils.login(self)
        category = utils.create_category()
        topic = utils.create_topic(category=category, user=self.user)
        form_data = {"title": "foobar"}
        response = self.client.post(
            reverse("spirit:topic:update", kwargs={"pk": topic.pk}), form_data
        )
        self.assertRedirects(response, topic.get_absolute_url(), status_code=302)

    def test_topic_update_create_moderation_action(self):
        """
        POST, topic moved to category
        """
        utils.login(self)
        self.user.st.is_moderator = True
        self.user.save()

        category = utils.create_category()
        topic = utils.create_topic(category=category, user=self.user)
        category2 = utils.create_category()
        form_data = {"title": "foobar", "category": category2.pk}
        self.client.post(
            reverse("spirit:topic:update", kwargs={"pk": topic.pk}), form_data
        )
        self.assertEqual(
            len(
                Comment.objects.filter(
                    user=self.user, topic_id=topic.pk, action=Comment.MOVED
                )
            ),
            1,
        )

    def test_topic_update_invalid_user(self):
        """
        POST, update topic
        """
        utils.login(self)
        category = utils.create_category()
        topic = utils.create_topic(category=category)
        form_data = {"title": "foobar"}
        response = self.client.post(
            reverse("spirit:topic:update", kwargs={"pk": topic.pk}), form_data
        )
        self.assertEqual(response.status_code, 404)

    def test_topic_detail_view(self):
        """
        should display topic with comments
        """
        utils.login(self)
        category = utils.create_category()

        topic = utils.create_topic(category=category)
        topic2 = utils.create_topic(category=category)

        comment1 = utils.create_comment(topic=topic)
        comment2 = utils.create_comment(topic=topic)
        utils.create_comment(topic=topic2)

        response = self.client.get(
            reverse("spirit:topic:detail", kwargs={"pk": topic.pk, "slug": topic.slug})
        )
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.context["topic"], topic)
        self.assertEqual(list(response.context["comments"]), [comment1, comment2])

    @override_djconfig(comments_per_page=2)
    def test_topic_detail_view_paginate(self):
        """
        should display topic with comments, page 1
        """
        utils.login(self)
        category = utils.create_category()

        topic = utils.create_topic(category=category)

        comment1 = utils.create_comment(topic=topic)
        comment2 = utils.create_comment(topic=topic)
        utils.create_comment(topic=topic)  # comment3

        response = self.client.get(
            reverse("spirit:topic:detail", kwargs={"pk": topic.pk, "slug": topic.slug})
        )
        self.assertEqual(response.status_code, 200)
        self.assertEqual(list(response.context["comments"]), [comment1, comment2])

    def test_topic_detail_viewed(self):
        """
        Calls utils.topic_viewed
        """

        def mocked_topic_viewed(request, topic):
            self._user = request.user
            self._topic = topic

        org_viewed, utils_topic.topic_viewed = (
            utils_topic.topic_viewed,
            mocked_topic_viewed,
        )
        try:
            utils.login(self)
            category = utils.create_category()
            topic = utils.create_topic(category=category, user=self.user)
            response = self.client.get(
                reverse(
                    "spirit:topic:detail", kwargs={"pk": topic.pk, "slug": topic.slug}
                )
            )
            self.assertEqual(response.status_code, 200)
            self.assertEqual(self._topic, topic)
            self.assertEqual(self._user, self.user)
        finally:
            utils_topic.topic_viewed = org_viewed

    def test_topic_detail_view_invalid_slug(self):
        """
        invalid slug
        """
        utils.login(self)
        category = utils.create_category()
        topic = utils.create_topic(category=category)
        response = self.client.get(
            reverse("spirit:topic:detail", kwargs={"pk": topic.pk, "slug": "bar"})
        )
        self.assertRedirects(response, topic.get_absolute_url(), status_code=301)

    def test_topic_detail_view_no_slug(self):
        """
        no slug
        """
        utils.login(self)
        category = utils.create_category()
        topic = utils.create_topic(category=category)
        response = self.client.get(
            reverse("spirit:topic:detail", kwargs={"pk": topic.pk, "slug": ""})
        )
        self.assertRedirects(response, topic.get_absolute_url(), status_code=301)

    def test_topic_active_view(self):
        """
        topics ordered by activity
        """
        category = utils.create_category()
        topic_a = utils.create_topic(category=category)
        topic_b = utils.create_topic(category=category, user=self.user, view_count=10)
        topic_c = utils.create_topic(category=category)

        Topic.objects.filter(pk=topic_a.pk).update(
            last_active=timezone.now() - datetime.timedelta(days=10)
        )
        Topic.objects.filter(pk=topic_c.pk).update(
            last_active=timezone.now() - datetime.timedelta(days=5)
        )

        response = self.client.get(reverse("spirit:topic:index-active"))
        self.assertEqual(list(response.context["topics"]), [topic_b, topic_c, topic_a])

    def test_topic_active_view_pinned(self):
        """
        Show globally pinned topics first,
        regular pinned topics are shown as regular topics
        """
        category = utils.create_category()
        topic_a = utils.create_topic(category=category)
        topic_b = utils.create_topic(category=category, is_pinned=True)
        topic_c = utils.create_topic(category=category)
        topic_d = utils.create_topic(category=category, is_globally_pinned=True)
        # show globally pinned first
        Topic.objects.filter(pk=topic_d.pk).update(
            last_active=timezone.now() - datetime.timedelta(days=10)
        )

        response = self.client.get(reverse("spirit:topic:index-active"))
        self.assertEqual(
            list(response.context["topics"]), [topic_d, topic_c, topic_b, topic_a]
        )

    def test_topic_active_view_dont_show_private_or_removed(self):
        """
        dont show private topics or removed
        """
        category = utils.create_category()
        category_removed = utils.create_category(is_removed=True)
        subcategory = utils.create_category(parent=category_removed)
        subcategory_removed = utils.create_category(parent=category, is_removed=True)
        utils.create_private_topic()
        utils.create_topic(category=category, is_removed=True)
        utils.create_topic(category=category_removed)
        utils.create_topic(category=subcategory)
        utils.create_topic(category=subcategory_removed)

        response = self.client.get(reverse("spirit:topic:index-active"))
        self.assertEqual(list(response.context["topics"]), [])

    def test_topic_active_view_dont_show_not_global(self):
        """
        Should not display non-global categories topics
        """
        # Global subcategories from non-global categories should be displayed
        category_non_global = utils.create_category(is_global=False)
        subcategory_global = utils.create_category(parent=category_non_global)
        utils.create_topic(category=category_non_global)
        topic = utils.create_topic(category=subcategory_global)

        response = self.client.get(reverse("spirit:topic:index-active"))
        self.assertEqual(list(response.context["topics"]), [topic])

    def test_topic_active_view_bookmark(self):
        """
        topics with bookmarks
        """
        utils.login(self)
        category = utils.create_category()
        topic = utils.create_topic(category=category, user=self.user)
        bookmark = CommentBookmark.objects.create(topic=topic, user=self.user)

        user2 = utils.create_user()
        CommentBookmark.objects.create(topic=topic, user=user2)

        topic2 = utils.create_topic(category=category, user=self.user)
        CommentBookmark.objects.create(topic=topic2, user=self.user)
        ten_days_ago = timezone.now() - datetime.timedelta(days=10)
        Topic.objects.filter(pk=topic2.pk).update(last_active=ten_days_ago)

        response = self.client.get(reverse("spirit:topic:index-active"))
        self.assertEqual(list(response.context["topics"]), [topic, topic2])
        self.assertEqual(response.context["topics"][0].bookmark, bookmark)

    @override_djconfig(topics_per_page=1)
    def test_topic_active_view_paginate(self):
        """
        topics ordered by activity paginated
        """
        category = utils.create_category()
        _topic_a = utils.create_topic(category=category)
        topic_b = utils.create_topic(category=category, user=self.user, view_count=10)

        response = self.client.get(reverse("spirit:topic:index-active"))
        self.assertEqual(list(response.context["topics"]), [topic_b])

    def test_index_active_categories(self):
        default_cats = list(utils.default_categories())
        cat1 = utils.create_category()
        utils.create_category(parent=cat1)
        utils.create_category(is_private=True)
        utils.create_category(is_removed=True)
        response = self.client.get(reverse("spirit:topic:index-active"))
        self.assertEqual(
            set(response.context["categories"]), set(default_cats + [cat1])
        )

    @override_settings(ST_ORDERED_CATEGORIES=True)
    def test_index_active_ordered(self):
        utils.default_categories().delete()
        cat1 = utils.create_category(title="1", sort=2)
        cat2 = utils.create_category(title="2", sort=1)
        response = self.client.get(reverse("spirit:topic:index-active"))
        self.assertEqual(list(response.context["categories"]), [cat2, cat1])
        cat1.sort = 0
        cat1.save()
        response = self.client.get(reverse("spirit:topic:index-active"))
        self.assertEqual(list(response.context["categories"]), [cat1, cat2])

    @override_settings(ST_ORDERED_CATEGORIES=False)
    def test_index_active_title_order(self):
        utils.default_categories().delete()
        cat1 = utils.create_category(title="1", sort=2)
        cat2 = utils.create_category(title="2", sort=1)
        response = self.client.get(reverse("spirit:topic:index-active"))
        self.assertEqual(list(response.context["categories"]), [cat1, cat2])


class TopicFormTest(TestCase):
    def setUp(self):
        utils.cache_clear()
        self.user = utils.create_user()

    def test_topic_publish(self):
        """
        create topic
        """
        category = utils.create_category()
        subcategory = utils.create_subcategory(category)
        form_data = {"comment": "foo", "title": "foobar", "category": subcategory.pk}
        form = TopicForm(self.user, data=form_data)
        self.assertEqual(form.is_valid(), True)

    def test_topic_publish_invalid_closed_subcategory(self):
        """
        invalid closed subcategory
        """
        category = utils.create_category()
        subcategory = utils.create_subcategory(category, is_closed=True)
        form_data = {"comment": "foo", "title": "foobar", "category": subcategory.pk}
        form = TopicForm(self.user, data=form_data)
        self.assertEqual(form.is_valid(), False)
        self.assertNotIn("category", form.cleaned_data)

    def test_topic_publish_invalid_removed_subcategory(self):
        """
        invalid removed subcategory
        """
        category = utils.create_category()
        subcategory = utils.create_subcategory(category, is_removed=True)
        form_data = {"comment": "foo", "title": "foobar", "category": subcategory.pk}
        form = TopicForm(self.user, data=form_data)
        self.assertEqual(form.is_valid(), False)
        self.assertNotIn("category", form.cleaned_data)

    def test_topic_update(self):
        """
        create update
        """
        category = utils.create_category()
        topic = utils.create_topic(category)
        form_data = {"title": "foobar"}
        form = TopicForm(self.user, data=form_data, instance=topic)
        self.assertEqual(form.is_valid(), True)

    def test_topic_update_moderator(self):
        category = utils.create_category()
        topic = utils.create_topic(category)
        self.user.st.is_moderator = True
        self.user.st.save()
        form = TopicForm(self.user, data=None, instance=topic)
        self.assertIn("category", form.fields)
        form = TopicForm(self.user, data=None)
        self.assertIn("category", form.fields)

    def test_topic_update_not_moderator(self):
        category = utils.create_category()
        topic = utils.create_topic(category)
        self.user.st.is_moderator = False
        self.user.st.save()
        form = TopicForm(self.user, data=None, instance=topic)
        self.assertNotIn("category", form.fields)
        form = TopicForm(self.user, data=None)
        self.assertIn("category", form.fields)

    def test_topic_get_category(self):
        """
        Should return the category
        """
        category = utils.create_category()
        form_data = {"title": "foobar", "category": category.pk}
        form = TopicForm(self.user, data=form_data)
        self.assertTrue(form.is_valid())
        self.assertEqual(form.get_category(), category)

    def test_topic_get_topic_hash(self):
        """
        Should return the topic hash
        """
        category = utils.create_category()
        title = "title foobar"
        form_data = {"title": title, "category": category.pk}
        form = TopicForm(self.user, data=form_data)
        self.assertTrue(form.is_valid())
        self.assertEqual(
            form.get_topic_hash(),
            hashlib.md5(
                "{}category-{}".format(title, category.pk).encode("utf-8")
            ).hexdigest(),
        )

    def test_topic_get_topic_hash_from_field(self):
        """
        Should return the topic hash from form field
        """
        category = utils.create_category()
        topic_hash = "1" * 32
        form_data = {
            "title": "foobar",
            "category": category.pk,
            "topic_hash": topic_hash,
        }
        form = TopicForm(self.user, data=form_data)
        self.assertTrue(form.is_valid())
        self.assertEqual(form.get_topic_hash(), topic_hash)

    def test_topic_updates_reindex_at(self):
        """
        Should update reindex_at field
        """
        yesterday = timezone.now() - datetime.timedelta(days=1)
        category = utils.create_category()
        topic = utils.create_topic(category, reindex_at=yesterday)
        self.assertEqual(topic.reindex_at, yesterday)

        form_data = {"title": "foobar"}
        form = TopicForm(self.user, data=form_data, instance=topic)
        self.assertEqual(form.is_valid(), True)
        form.save()
        self.assertGreater(Topic.objects.get(pk=topic.pk).reindex_at, yesterday)

    @override_settings(ST_ORDERED_CATEGORIES=True)
    def test_category_ordered(self):
        utils.default_categories().delete()
        cat1 = utils.create_category(title="1", sort=2)
        cat2 = utils.create_category(title="2", sort=1)
        form = TopicForm(self.user, data=None)
        self.assertEqual(list(form.fields["category"].queryset), [cat2, cat1])
        cat1.sort = 0
        cat1.save()
        form = TopicForm(self.user, data=None)
        self.assertEqual(list(form.fields["category"].queryset), [cat1, cat2])

    @override_settings(ST_ORDERED_CATEGORIES=False)
    def test_category_title_order(self):
        utils.default_categories().delete()
        cat1 = utils.create_category(title="1", sort=2)
        cat2 = utils.create_category(title="2", sort=1)
        cat3 = utils.create_category(title="3", sort=3)
        cat0 = utils.create_category(title="0", sort=0)
        form = TopicForm(self.user, data=None)
        self.assertEqual(
            list(form.fields["category"].queryset), [cat0, cat1, cat2, cat3]
        )


class TopicUtilsTest(TestCase):
    def setUp(self):
        utils.cache_clear()
        self.user = utils.create_user()

    def test_topic_viewed(self):
        """
        * Should update/create the comment bookmark
        * Should mark the topic notification as read
        * Should create or mark the topic (unread) as read
        * Should increase the view_counter
        """
        req = RequestFactory().get("/?page=1")
        req.user = self.user

        category = utils.create_category()
        topic = utils.create_topic(category=category, user=self.user)
        comment = utils.create_comment(topic=topic)
        notification = TopicNotification.objects.create(
            user=topic.user, topic=topic, comment=comment, is_read=False
        )
        unread = TopicUnread.objects.create(user=topic.user, topic=topic, is_read=False)
        utils_topic.topic_viewed(req, topic)
        self.assertEqual(
            len(CommentBookmark.objects.filter(user=self.user, topic=topic)), 1
        )
        self.assertTrue(TopicNotification.objects.get(pk=notification.pk).is_read)
        self.assertTrue(TopicUnread.objects.get(pk=unread.pk).is_read)
        self.assertEqual(Topic.objects.get(pk=topic.pk).view_count, 1)


class TopicModelsTest(TestCase):
    def setUp(self):
        utils.cache_clear()
        self.user = utils.create_user()
        self.category = utils.create_category()
        self.topic = utils.create_topic(category=self.category, user=self.user)

    def test_topic_increase_view_count(self):
        """
        increase_view_count
        """
        self.topic.increase_view_count()
        self.assertEqual(Topic.objects.get(pk=self.topic.pk).view_count, 1)

    def test_topic_increase_comment_count(self):
        """
        increase_comment_count
        """
        self.topic.increase_comment_count()
        self.assertEqual(Topic.objects.get(pk=self.topic.pk).comment_count, 1)
        self.assertGreater(
            Topic.objects.get(pk=self.topic.pk).last_active, self.topic.last_active
        )

    def test_topic_decrease_comment_count(self):
        """
        decrease_comment_count
        """
        Topic.objects.filter(pk=self.topic.pk).update(comment_count=10)
        self.topic.decrease_comment_count()
        self.assertEqual(Topic.objects.get(pk=self.topic.pk).comment_count, 9)

    def test_topic_new_comments_count(self):
        """
        Should return the new replies count
        """
        utils.login(self)
        category = utils.create_category()
        topic = utils.create_topic(category=category, user=self.user, comment_count=1)

        self.assertEqual(
            Topic.objects.filter(pk=topic.pk)
            .with_bookmarks(self.user)
            .first()
            .new_comments_count,
            0,
        )

        CommentBookmark.objects.create(topic=topic, user=self.user, comment_number=1)
        self.assertEqual(
            Topic.objects.filter(pk=topic.pk)
            .with_bookmarks(self.user)
            .first()
            .new_comments_count,
            0,
        )

        Topic.objects.filter(pk=topic.pk).update(comment_count=2)
        self.assertEqual(
            Topic.objects.filter(pk=topic.pk)
            .with_bookmarks(self.user)
            .first()
            .new_comments_count,
            1,
        )

        # topic.comment_count greater than bookmark.comment_number
        # should return 0
        Topic.objects.filter(pk=topic.pk).update(comment_count=0)
        self.assertEqual(
            Topic.objects.filter(pk=topic.pk)
            .with_bookmarks(self.user)
            .first()
            .new_comments_count,
            0,
        )

    def test_topic_has_new_comments(self):
        """
        Should return True when there are new replies
        """
        utils.login(self)
        category = utils.create_category()
        topic = utils.create_topic(category=category, user=self.user, comment_count=1)

        self.assertFalse(
            Topic.objects.filter(pk=topic.pk)
            .with_bookmarks(self.user)
            .first()
            .has_new_comments
        )

        CommentBookmark.objects.create(topic=topic, user=self.user, comment_number=1)
        self.assertFalse(
            Topic.objects.filter(pk=topic.pk)
            .with_bookmarks(self.user)
            .first()
            .has_new_comments
        )

        Topic.objects.filter(pk=topic.pk).update(comment_count=2)
        self.assertTrue(
            Topic.objects.filter(pk=topic.pk)
            .with_bookmarks(self.user)
            .first()
            .has_new_comments
        )

    def test_topic_is_visited(self):
        """
        Should return True when the topic has been visited
        """
        utils.login(self)
        category = utils.create_category()
        topic = utils.create_topic(category=category, user=self.user)

        self.assertFalse(
            Topic.objects.filter(pk=topic.pk)
            .with_bookmarks(self.user)
            .first()
            .is_visited
        )

        CommentBookmark.objects.create(topic=topic, user=self.user)
        self.assertTrue(
            Topic.objects.filter(pk=topic.pk)
            .with_bookmarks(self.user)
            .first()
            .is_visited
        )

    def test_topic_get_bookmark_url(self):
        """
        Should return the bookmark url
        """
        utils.login(self)
        category = utils.create_category()
        topic = utils.create_topic(category=category, user=self.user)

        # No bookmark
        topic_with_bookmark = (
            Topic.objects.filter(pk=topic.pk).with_bookmarks(self.user).first()
        )
        self.assertEqual(
            topic_with_bookmark.get_bookmark_url(),
            topic_with_bookmark.get_absolute_url(),
        )

        # With bookmark
        CommentBookmark.objects.create(topic=topic, user=self.user, comment_number=1)
        topic_with_bookmark2 = (
            Topic.objects.filter(pk=topic.pk).with_bookmarks(self.user).first()
        )
        self.assertEqual(
            topic_with_bookmark2.get_bookmark_url(),
            topic_with_bookmark2.bookmark.get_absolute_url(),
        )

        # With bookmark and new comment
        Topic.objects.filter(pk=topic.pk).update(comment_count=2)
        topic_with_bookmark3 = (
            Topic.objects.filter(pk=topic.pk).with_bookmarks(self.user).first()
        )
        self.assertEqual(
            topic_with_bookmark3.get_bookmark_url(),
            topic_with_bookmark3.bookmark.get_new_comment_url(),
        )
